package com.niit.mall.user.service.impl;


import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.niit.mall.api.client.AddressClient;
import com.niit.mall.api.client.ProductClient;
import com.niit.mall.api.domain.vo.AddressVO;

import com.niit.mall.common.domain.dto.PageDTO;
import com.niit.mall.common.exception.Asserts;
import com.niit.mall.common.utils.UserContext;
import com.niit.mall.mall.auth.config.JwtProperties;
import com.niit.mall.mall.auth.utils.JwtTool;
import com.niit.mall.user.domain.dto.UserInfoDTO;
import com.niit.mall.user.domain.dto.UserLoginDTO;
import com.niit.mall.user.domain.enums.UserStatus;
import com.niit.mall.user.domain.po.Role;
import com.niit.mall.user.domain.po.User;
import com.niit.mall.user.domain.po.UserInfo;
import com.niit.mall.user.domain.po.UserLoginLog;
import com.niit.mall.user.domain.query.RoleQuery;
import com.niit.mall.user.domain.query.UserQuery;
import com.niit.mall.user.domain.vo.*;
import com.niit.mall.user.mapper.UserInfoMapper;
import com.niit.mall.user.mapper.UserLoginLogMapper;
import com.niit.mall.user.mapper.UserMapper;
import com.niit.mall.user.service.IUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;

/**
 * @BelongsProject: pardo_mall_backend
 * @BelongsPackage: com.niit.mall.admin.service.serviceImpl
 * @Author: ChuXuan
 * @CreateTime: 2025-05-21  21:06
 * @Description: 用户服务实现类
 * @Version: 1.0
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
	
	/**
	 * 密码编码器
	 */
	private final PasswordEncoder passwordEncoder;
	
	/**
	 * JSON Web Token（JWT）工具类实例
	 */
	private final JwtTool jwtTool;
	
	/**
	 * JWT属性配置
	 */
	private final JwtProperties jwtProperties;
	
	/**
	 * 用户登录日志映射器
	 */
	private final UserLoginLogMapper userLoginLogMapper;

	/**
	 * 地址客户端实例
	 */
	private final AddressClient addressClient;
	
	private final UserInfoMapper userInfoMapper;

	/**
	 * 用户映射器
	 */
	private final UserMapper userMapper;

	/**
	 * 产品客户端实例
	 */
	private final ProductClient productClient;


//	/**
//	 * 扣减用户余额方法。
//	 *
//	 * @param id    用户ID
//	 * @param money 扣减的金额
//	 * @return 扣减操作的结果信息
//	 * @throws RuntimeException 如果用户不存在、用户已冻结或者用户余额不足
//	 */
//	@Override
//	public String deductionUserBalance(Long id, Integer money) {
//		// 根据id  查询用户
//		User user = userMapper.selectById(id);
//		User user = getById(id);
//		// 校验用户状态
//		if(user == null){
//			throw new RuntimeException("用户不存在");
//		}
//		if(user.getStatus() == UserStatus.FROZEN){
//			throw new RuntimeException("用户已冻结");
//		}
//
//		baseMapper.updateBalance(id,money);
//		return "扣减成功";
//
//	}

//	/**
//	 * 根据用户名、状态和余额范围查询用户列表的方法。
//	 *
//	 * @param username   用户名，非空时进行模糊查询
//	 * @param status     用户状态，非空时进行等值查询
//	 * @param minBalance 最低余额，非空时查询余额大于该值的用户
//	 * @param maxBalance 最高余额，非空时查询余额小于该值的用户
//	 * @return 满足条件的用户列表
//	 */
//	@Override
//	public List<User> queryUsers(String username, Integer status, Integer minBalance, Integer maxBalance) {
//		List<User> userList = lambdaQuery()
//				                  .like(username != null, User::getUsername, username)
//				                  .eq(status != null, User::getStatus, status)
//				                  .gt(minBalance != null, User::getBalance, minBalance)
//				                  .lt(maxBalance != null, User::getBalance, maxBalance)
//				                  .list();
//		return userList;
//	}

	/**
	 * 根据用户查询条件分页查询用户信息。
	 *
	 * @param query 用户查询条件对象，包含分页信息和查询条件
	 * @return 分页后的用户视图对象列表
	 */
	@Override
	public PageDTO<UserVO> queryUserPage(UserQuery query) {
		
		// 获取查询条件
		String keyword = query.getKeyword();
		Integer status = query.getStatus();
		String sortBy = query.getSortBy();
		Boolean isAsc = query.getIsAsc();
		// 分页条件
		Page<User> page = query.toMpPageDefaultByUpdateDate();;

		// 构建查询条件并执行查询
		Page<User> userPage = lambdaQuery()
				.like(keyword != null, User::getUsername, keyword)
				.or()
				.like(keyword != null, User::getPhone, keyword)
				.eq(status != null, User::getStatus, status)
				.page(page);
		// 封装VO
		return PageDTO.of(userPage, UserVO.class);
	}
	
	
	/**
	 * 登录方法，用于用户登录并返回登录信息。
	 *
	 * @param loginDTO 用户登录数据传输对象，包含登录关键词和密码
	 * @return 用户登录结果视图对象，包含用户信息和登录令牌
	 * @throws IllegalArgumentException 当用户不存在、用户状态为冻结或密码错误时抛出异常
	 */
	@Override
	public UserLoginVO login(UserLoginDTO loginDTO) {
		// 获取字段
		String keyword = loginDTO.getKeyword();
		String password = loginDTO.getPassword();
		// 根据用户名|手机号查询用户
		User user = lambdaQuery()
				.eq(User::getUsername, keyword)
				.or()
				.eq(User::getPhone, keyword)
				.one();
		if (user == null){
	
			Asserts.fail("用户不存在");
		}
		if(user.getStatus()== UserStatus.FROZEN){
			Asserts.fail("用户已冻结");
		}
		if(!passwordEncoder.matches(password, user.getPassword())){
			Asserts.fail("密码不正确！");
//			throw new BadRequestException("密码错误");
		}
		// 生成token
		String token = jwtTool.createToken(user.getId(), jwtProperties.getTokenTTL());
		System.out.println(token);
		UserLoginVO userLoginVO = new UserLoginVO();
		userLoginVO.setToken(token);
		userLoginVO.setUserId(user.getId());
		userLoginVO.setUsername(user.getUsername());

		// 写入登录日志
		insertLoginLog(user);
		return userLoginVO;
	}
	
	/**
	 * 插入登录日志
	 *
	 * @param user 用户对象，用于获取用户信息
	 */
	public void insertLoginLog(User user){
		UserLoginLog userLoginLog = new UserLoginLog();
		// 获取当前时间
		Date now = new Date();
		userLoginLog.setUserId(user.getId());
		userLoginLog.setCreateTime(LocalDateTime.now());
		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attributes.getRequest();
		userLoginLog.setIp(request.getRemoteAddr());
		userLoginLogMapper.insert(userLoginLog);
		// 修改登录状态
		baseMapper.updateOnlineStatus(user.getId(),1, now);
	
	}
	
	
	/**
	 * 检查关键字是否重复的方法
	 *
	 * @param keyword 关键字，用于检查用户名或手机号是否重复
	 * @return 如果存在重复记录返回true，否则返回false
	 */
	@Override
	public boolean checkRepeat(String keyword) {
		User  user = lambdaQuery()
				.eq(User::getUsername, keyword)
				.or()
				.eq(User::getPhone, keyword)
				.one();
		return user != null;
	}
	
	/**
	 * 根据用户ID查询用户及其地址信息
	 *
	 * @param id 用户ID
	 * @return 用户视图对象，包含用户信息和地址列表
	 * @throws IllegalArgumentException 当用户不存在或用户状态为冻结时抛出异常
	 */
	@Override
	public UserVO queryUserAndAddressById(Long id) {
		// 查询用户
		User user = getById(id);
		if(user == null){
			throw new IllegalArgumentException("用户不存在");
		}
		if(user.getStatus() == UserStatus.FROZEN){
			throw  new IllegalArgumentException("用户已冻结");
		}
		UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
		// 查询用户信息
		UserInfo userInfo = userInfoMapper.selectById(id);

		// 查询用户优惠券数量
		Long couponNum = productClient.getCouponNum(id);
		userInfo.setCouponQuantity(couponNum);

		// 查询地址
		List<AddressVO> addressList = addressClient.queryAddressByUserId(id);

		UserInfoVO userInfoVO = BeanUtil.copyProperties(userInfo, UserInfoVO.class);
		userVO.setUserInfo(userInfoVO);
		
		userVO.setAddressList(addressList);
		return userVO;
	}
	
	/**
	 * 更新用户信息的方法
	 *
	 * @param userId      用户ID
	 * @param userInfoDTO 用户信息数据传输对象
	 */
	@Override
	public void updateUserInfo(Long userId, UserInfoDTO userInfoDTO) {
		UserInfo userInfo = BeanUtil.copyProperties(userInfoDTO, UserInfo.class);
		LocalDate now = LocalDate.now();
		userInfo.setUpdateDate(now);
		QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>().eq("user_id", userId);
		userInfoMapper.update(userInfo, queryWrapper);
	}
	
	/**
	 * 注销用户登录状态。
	 * <p>
	 * 更新指定用户的在线状态为离线。
	 *
	 * @throws RuntimeException 如果在更新过程中发生错误
	 */
	@Override
	public void logout() {
		Long userId = UserContext.getUser();
		Date now = new Date();
		userMapper.updateOnlineStatus(userId,0,now);
	}

}
